package com.health.system.aspect;


import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.health.system.annotation.Log;
import com.health.system.common.result.Result;
import com.health.system.common.utils.*;
import com.health.system.entity.HealthLog;
import com.health.system.service.LogService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 */
@Component
@Aspect
public class OperationLogAspect {
    @Autowired
    private LogService logService;

    @Pointcut("@annotation(com.health.system.annotation.Log)")
    public void pointcut() {
        // Log注解切入点位置
    }

    @AfterReturning(pointcut = "pointcut()", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        HealthLog log = buildLog(joinPoint, result, null, 0);
        logService.asyncInsert(log);
    }

    @AfterThrowing(pointcut = "pointcut()", throwing = "e")
    public void afterThrowing(JoinPoint joinPoint, Throwable e) {
        HealthLog log = buildLog(joinPoint, null, e, 1);
        logService.asyncInsert(log);
    }

    private HealthLog buildLog(JoinPoint joinPoint, Object result, Throwable e, int type) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        String tag = getApiTag(signature);
        String operationValue = getApiOperationValue(method);
        String logType = getLogType(method);

        HttpServletRequest request = ServletRequestUtil.getRequest();

        return HealthLog.builder()
                .type(type)
                .optModule(tag)
                .optType(logType)
                .optUrl(request.getRequestURI())
                .optMethod(joinPoint.getTarget().getClass().toString() + "." + method.getName())
                .optDesc(operationValue)
                .requestMethod(request.getMethod())
                .requestParam(JsonUtil.writer(joinPoint.getArgs()))
                .responseData(getResponseData(result, e))
                .exceptionDetail(ThrowableUtil.getStackTrace(e).getBytes())
                .userId(UserAuthUtil.authId())
                .nickname(UserAuthUtil.nickName())
                .ipAddress(IpUtil.getIpAddress())
                .ipSource(IpUtil.getIpSource())
                .build();
    }

    private String getResponseData(Object result, Throwable e) {
        if (ObjectUtils.isNull(e)) {
            return JsonUtil.writer(result);
        }

        return JsonUtil.writer(Result.fail(e.getMessage()));
    }

    private String getLogType(Method method) {
        Log log = AnnotationUtils.getAnnotation(method, Log.class);

        if (log != null && StringUtils.isNotBlank(log.type())) {
            return log.type();
        }

        return "";
    }

    private String getApiOperationValue(Method method) {
        ApiOperation apiOperation = AnnotationUtils.getAnnotation(method, ApiOperation.class);

        if (apiOperation != null) {
            return apiOperation.value();
        }

        return "";
    }

    private String getApiTag(MethodSignature signature) {
        Api api = AnnotationUtils.getAnnotation(signature.getDeclaringType(), Api.class);

        if (api != null) {
            return api.tags()[0];
        }

        return "";
    }



}
